package com.ybear.ybnetworkutil.http;

import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.ybear.ybnetworkutil.call.CallDownloadListener;
import com.ybear.ybnetworkutil.call.CallReqListener;
import com.ybear.ybnetworkutil.call.Callback;
import com.ybear.ybnetworkutil.call.CallbackString;
import com.ybear.ybnetworkutil.request.Param;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * 请求设置
 */
public class Req {
    private final Header mHeader;
    private OkHttpClient mClient;
    private Request.Builder mReqBuild;
    private boolean isEnableEveryRequestClearHeader = true;
    private final List<CallReqListener> mCallReqList = new ArrayList<>();

    private final CallReqListener mCallReqDataListener = new CallReqListener() {
        @Override
        public void onRequest(@NonNull com.ybear.ybnetworkutil.request.Request r) {
            for( CallReqListener l : mCallReqList ) {
                if( l != null ) l.onRequest( r );
            }
        }
        @Override
        public void onResult(String url, String result) {
            for( CallReqListener l : mCallReqList ) {
                if( l != null ) l.onResult( url, result );
            }
        }
        @Override
        public void onFailure(@NonNull Call call, @NonNull IOException e) {
            for( CallReqListener l : mCallReqList ) {
                if( l != null ) l.onFailure( call, e );
            }
        }
        @Override
        public void onResponse(@NonNull Call call, @NonNull Response r) throws IOException {
            for( CallReqListener l : mCallReqList ) {
                if( l != null ) l.onResponse( call, r );
            }
        }
    };

    private Req() { mHeader = Header.create(); }
    public static Req create() { return new Req(); }

    Req initClient(OkHttpClient client, HttpReboot reboot) {
        clearReqDataListener();
        mClient = client;
        mReqBuild = new Request.Builder();
        if( reboot != null ) reboot.initReq( this );
        return this;
    }

    /**
     * 是否启用每次请求之后清空头信息
     * @param enable        是否启用
     */
    public void enableEveryRequestClearHeader(boolean enable) {
        isEnableEveryRequestClearHeader = enable;
    }

    /**
     * 连接最长等待时间
     * @return  毫秒
     */
    public int connectTimeoutMillis() { return mClient.connectTimeoutMillis(); }

    /**
     * 读取最长等待时间
     * @return  毫秒
     */
    public int readTimeoutMillis() { return mClient.readTimeoutMillis(); }

    /**
     * 写入最长等待时间
     * @return  毫秒
     */
    public int writeTimeoutMillis() { return mClient.writeTimeoutMillis(); }

    /**
     * 回调最长等待时间
     * @return  毫秒
     */
    public int callTimeoutMillis() { return mClient.callTimeoutMillis(); }

    /**
     * 添加头信息
     * @param name      key
     * @param value     val
     * @return          this
     */
    public Req addHeader(String name, String value) {
        mHeader.add(name, value);
        return this;
    }
    /**
     * 添加头信息
     * @param name      key
     * @param value     val
     * @return          this
     */
    public Req addHeader(String name, Date value) {
        mHeader.add(name, value);
        return this;
    }
    /**
     * 添加头信息
     * @param line      分隔符 “:”
     * @return          this
     */
    public Req addHeader(String line) {
        mHeader.add(line);
        return this;
    }

    /**
     * 覆盖现有头信息
     * @param name      key
     * @param value     val
     * @return          this
     */
    public Req putHeader(String name, String value) {
        mHeader.set(name, value);
        return this;
    }
    /**
     * 覆盖现有头信息
     * @param name      key
     * @param value     val
     * @return          this
     */
    public Req putHeader(String name, Date value) {
        mHeader.set(name, value);
        return this;
    }

    /**
     * 添加所有Header
     * @param header    添加当前header
     * @return          this
     */
    public Req headers(Header header) {
        mHeader.addAll( header );
        return this;
    }

    /**
     * 添加监听请求
     * @param l     回调
     * @return      this
     */
    public Req addReqDataListener(CallReqListener l) {
        mCallReqList.add( l );
        return this;
    }

    /**
     * 移除监听请求
     * @param l     回调
     * @return      this
     */
    public Req removeReqDataListener(CallReqListener l) {
        mCallReqList.remove( l );
        return this;
    }

    /**
     * 清空所有监听请求
     * @return      this
     */
    public Req clearReqDataListener() {
        mCallReqList.clear();
        return this;
    }

    /**
     * 设置请求
     * @param request   请求(包含地址、参数、回调)
     * @return          this
     */
    public ClientBuilder req(@NonNull com.ybear.ybnetworkutil.request.Request request) {
        ClientBuilder b = new ClientBuilder( mClient, mReqBuild, request, mCallReqDataListener );
        //添加头信息
        mReqBuild.headers( mHeader.callHeader() );
        //清空
        if( isEnableEveryRequestClearHeader ) mHeader.clear();
        return b;
    }

    /**
     * 设置请求
     * @param url                   地址
     * @param param                 参数
     * @param callbackEntity        回调实体类
     * @return                      this
     */
    private ClientBuilder req(@Nullable String url,
                              @Nullable String param,
                              @Nullable CallbackEntity callbackEntity) {
        com.ybear.ybnetworkutil.request.Request r = new com.ybear.ybnetworkutil.request.Request() {
            public String url() { return url; }
            public String api() { return null; }
        };
        r.setParam( param );
        if( callbackEntity != null ) {
            r.setCallback( callbackEntity.getCallback() );
            r.setCallbackString( callbackEntity.getCallbackString() );
            r.setCallDownloadListener( callbackEntity.getCallDownloadListener() );
        }
        return req( r );
    }

    /**
     * 设置请求
     * @param url       地址
     * @param param     参数
     * @param call      回调
     * @return          this
     */
    public ClientBuilder req(String url, String param, @Nullable CallbackString call) {
        return req(url, param, new CallbackEntity( call ) );
    }

    /**
     * 设置请求
     * @param url       地址
     * @param param     参数
     * @param call      回调
     * @return          this
     */
    public ClientBuilder req(String url, String param, @Nullable Callback call) {
        return req(url, param, new CallbackEntity( call ) );
    }

    /**
     * 设置请求
     * @param url       地址
     * @param param     参数
     * @return          this
     */
    public ClientBuilder req(String url, String param) {
        return req(url, param, (CallbackEntity) null );
    }
    /**
     * 设置请求
     * @param url       地址
     * @param param     参数
     * @return          this
     */
    public ClientBuilder req(String url, Map<String, Object> param) {
        return req( url, new Param( param ).toParamString() );
    }

    private ClientBuilder req(String url, @Nullable CallbackEntity callbackEntity ) {
        if( TextUtils.isEmpty( url ) || !url.contains( "?" ) ) {
            return req( url, null, callbackEntity );
        }
        String[] spReq = url.split( "\\?" );
        return req( spReq[ 0 ], spReq[ 1 ], callbackEntity );
    }

    /**
     * 设置请求
     * @param url       地址
     * @param call      回调
     * @return          this
     */
    public ClientBuilder req(String url, @Nullable CallbackString call) {
        return req( url, new CallbackEntity( call ) );
    }

    /**
     * 设置请求
     * @param url       地址
     * @param call      回调
     * @return          this
     */
    public ClientBuilder req(String url, @Nullable Callback call) {
        return req( url, new CallbackEntity( call ) );
    }

    /**
     * 设置请求
     * @param url       地址
     * @param call      回调
     * @return          this
     */
    public ClientBuilder req(String url, @Nullable CallDownloadListener call) {
        return req( url, new CallbackEntity( call ) );
    }

    /**
     * 设置请求
     * @param url       地址
     * @return          this
     */
    public ClientBuilder req(String url) { return req( url, (CallbackEntity) null ); }
}
